﻿using AutoMapper;
using QYmall.Core.Common.Emum;
using QYmall.Core.Common.Extensions;
using QYmall.Core.Common.Helper;
using QYmall.Core.DBFactory.Database;
using QYmall.Core.IServices;
using QYmall.Core.Model.Models;
using QYmall.Core.Model.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace QYmall.Core.Services
{
    /// <summary>
    /// 配送方式接口实现
    /// </summary>
    public class ShopDeliveryService : BaseService, IShopDeliveryService
    {
        private readonly IUserService _userService;
        private readonly IMapper _mapper;

        public ShopDeliveryService(IDbContextFactory contentFactory,
            IUserService userService, IMapper mapper) : base(contentFactory)
        {
            _userService = userService;
            _mapper = mapper;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<ShopDelivery?> QueryAsync(Expression<Func<ShopDelivery, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = await _context.Set<ShopDelivery>()
                .Include(x => x.DeliveryAreas)
                .FirstOrDefaultAsync(funcWhere);
            return result;
        }

        /// <summary>
        /// 查询指定数量列表
        /// </summary>
        public async Task<IEnumerable<ShopDelivery>> QueryListAsync(int top, Expression<Func<ShopDelivery, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var result = _context.Set<ShopDelivery>()
                .Include(x => x.DeliveryAreas)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 查询分页列表
        /// </summary>
        public async Task<PaginationList<ShopDelivery>> QueryPageAsync(int pageSize, int pageIndex, Expression<Func<ShopDelivery, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var result = _context.Set<ShopDelivery>()
                .Include(x => x.DeliveryAreas)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            return await PaginationList<ShopDelivery>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 添加一条记录
        /// </summary>
        public async Task<ShopDeliveryDto> AddAsync(ShopDeliveryEditDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //映射成实体
            var model = _mapper.Map<ShopDelivery>(modelDto);
            model.AddBy = await _userService.GetUserNameAsync();
            model.AddTime = DateTime.Now;
            //保存
            await _context.Set<ShopDelivery>().AddAsync(model);
            var result = await this.SaveAsync();
            if (!result)
            {
                throw new ResponseException("数据保存时发生意外错误");
            }
            //映射成DTO
            return _mapper.Map<ShopDeliveryDto>(model);
        }

        /// <summary>
        /// 修改一条记录
        /// </summary>
        public async Task<bool> UpdateAsync(long id, ShopDeliveryEditDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //根据ID获取记录
            var model = await _context.Set<ShopDelivery>().Where(x => x.Id == id)
                .Include(x => x.DeliveryAreas)
                .FirstOrDefaultAsync();
            //如果不存在则抛出异常
            if (model == null)
            {
                throw new ResponseException("数据不存在或已删除", ErrorCode.NotFound, StatusCodes.Status404NotFound);
            }
            //将DTO映射到源数据
            var mapModel = _mapper.Map(modelDto, model);
            //保存
            _context.Set<ShopDelivery>().Update(mapModel);
            var result = await this.SaveAsync();
            return result;
        }

        /// <summary>
        /// 根据条件删除记录
        /// </summary>
        public async Task<bool> DeleteAsync(Expression<Func<ShopDelivery, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var list = await _context.Set<ShopDelivery>()
                .Include(x => x.DeliveryAreas).Where(funcWhere).ToListAsync();
            if (list == null)
            {
                return false;
            }
            _context.Set<ShopDelivery>().RemoveRange(list);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 统计配送费用
        /// </summary>
        /// <param name="deliveryId">配送ID</param>
        /// <param name="province">省份名称</param>
        /// <param name="totalWeight">总重量(克)</param>
        /// <param name="isInsure">是否保价</param>
        /// <param name="insurePrice">保价金额</param>
        public async Task<ShopDeliveryTotalDto> QueryTotalAsync(int id, string? province, int totalWeight,
            byte isInsure, decimal insurePrice, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            if (!province.IsNotNullOrEmpty())
            {
                throw new ResponseException("请选择配送地区再查询");
            }
            //查询配送方式
            var model = await _context.Set<ShopDelivery>().Include(x => x.DeliveryAreas)
                .FirstOrDefaultAsync(x => x.Id == id && x.IsDelete == 0 && x.Status == 0);
            if (model == null)
            {
                // 统计配送费用配送方式
                throw new ResponseException("配送方式有误，请确认后操作");
            }
            if (model.IsInsure == 0 && isInsure > 0)
            {
                throw new ResponseException("当前配送方式不支持保价");
            }
            //创建待赋值实体
            ShopDeliveryTotalDto result = new()
            {
                Id = model.Id,
                Title = model.Title,
                Freight = model.FirstPrice
            };
            //重量为0时直接返回首重费用
            if (totalWeight == 0)
            {
                return result;
            }
            //转换成千克
            totalWeight = totalWeight > 1000 ? totalWeight / 1000 : 1;

            //计算配送费用
            decimal firstPrice = model.FirstPrice;//首重费用
            decimal secondPrice = model.SecondPrice;//续重费用
            decimal totalSecondPrice = 0;//续重总费用
            //如果符合自定义地区，采用地区费用
            var areaModel = model.DeliveryAreas.FirstOrDefault(x => x.Province == province);
            if (areaModel != null)
            {
                firstPrice = areaModel.FirstPrice;
                secondPrice = areaModel.SecondPrice;
            }
            //如果总重量大于首重才计算续重费用
            if (totalWeight > model.FirstWeight)
            {
                //续重重量=总重量-首重量
                decimal secondWeight = totalWeight - model.FirstWeight;
                //向上取整，只要有小数都加1
                //续重费用=(续重重量/续重量)*续重价格
                totalSecondPrice = Math.Ceiling(secondWeight / model.SecondWeight) * secondPrice;
            }
            //保价费用=保价金额*保价费率
            decimal insureFreight = 0;
            if (isInsure > 0)
            {
                insureFreight = insurePrice * ((decimal)model.InsureRate / 1000);
                if (insureFreight < model.InsurePrice)
                {
                    insureFreight = model.InsurePrice;//最低保价
                }
            }
            //总运费=首重费用+续重费用+保价费用
            result.Freight = firstPrice + totalSecondPrice + insureFreight;

            return result;
        }
    }
}
